package com.tanqidi.arcgisandroid.ui

import android.graphics.Point
import android.os.Environment
import android.text.TextUtils
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.esri.arcgisruntime.concurrent.ListenableFuture
import com.esri.arcgisruntime.data.*
import com.esri.arcgisruntime.geometry.Geometry
import com.esri.arcgisruntime.geometry.GeometryType
import com.esri.arcgisruntime.geometry.SpatialReference
import com.esri.arcgisruntime.layers.*
import com.esri.arcgisruntime.loadable.LoadStatus
import com.esri.arcgisruntime.mapping.view.MapView
import com.esri.arcgisruntime.ogc.kml.KmlDataset
import com.google.gson.Gson
import com.tanqidi.arcgisandroid.App
import com.tanqidi.arcgisandroid.R
import com.tanqidi.arcgisandroid.base.diyJetpack.BusMutableLiveData
import com.tanqidi.arcgisandroid.base.utils.*
import com.tanqidi.arcgisandroid.data.layerConfig.Layer.Companion.TYPE_POINT
import com.tanqidi.arcgisandroid.data.layerConfig.Layer.Companion.TYPE_POLYGON
import com.tanqidi.arcgisandroid.data.layerConfig.Layer.Companion.TYPE_POLYLINE
import com.tanqidi.arcgisandroid.data.project.Project
import com.tanqidi.arcgisandroid.data.project.ProjectRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import io.reactivex.rxjava3.core.Single
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.lang.RuntimeException
import javax.inject.Inject

@HiltViewModel
class HomeViewModel @Inject constructor(
    private val projectRepository: ProjectRepository
) : ViewModel() {

    private val MAP_TPK_INDEX = 0
    private val MAP_KML_INDEX = 1
    private val MAP_SHP_INDEX = 2
    private val MAP_GEODATABASE_INDEX = 3
    private val MAP_GEOJSON_INDEX = 4
    //这个index用来加载项目数据，geojson或者shp也或者featureServer，存储方式只用其中的一种，不能三种同时加载进来
    private val MAP_PROJECT_FEATURE_INDEX = 5
    //后面这个会移除
    private val MAP_FEATURE_SERVER_INDEX = 6

    //存储项目数据的FeatureTable
    private val featureTable = mutableMapOf<String, FeatureTable>()

    lateinit var mapView: MapView

    val queryFeatureLiveData = BusMutableLiveData<Feature>()

    fun getProjectByName(name: String) : Project {
        return projectRepository.getProjectByName(name)
    }

    suspend fun loadTpkToMapView() = withContext(Dispatchers.IO){
        val groupLayer = GroupLayer()
        getMapFromSPUtilsByResourceId(R.string.tpkMapJson)?.forEach {
            val fileName = it.key.toString()
            val filePath = it.value.toString()

            val tileCache = TileCache(filePath)
            val arcGISTiledLayer = ArcGISTiledLayer(tileCache)
            //把name也设置给layer，这样后续图层定位可以用到
            arcGISTiledLayer.name = fileName
            groupLayer.layers.add(arcGISTiledLayer)
        }
        addGroupLayerToMapViewOperationalLayers(groupLayer,MAP_TPK_INDEX)
    }

    suspend fun loadKmlToMapView() = withContext(Dispatchers.IO){
        val groupLayer = GroupLayer()
        getMapFromSPUtilsByResourceId(R.string.kmlMapJson)?.forEach {
            val fileName = it.key.toString()
            val filePath = it.value.toString()

            val kmlDataset = KmlDataset(filePath)
            val kmlLayer = KmlLayer(kmlDataset)
            //把name也设置给layer，这样后续图层定位可以用到
            kmlLayer.name = fileName
            groupLayer.layers.add(kmlLayer)
        }
        addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_KML_INDEX)
    }

    suspend fun loadShpToMapView() = withContext(Dispatchers.IO) {
        val groupLayer = GroupLayer()
        //是空的，groupLayer里面什么都没有只是存放进里面占个位置
        addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_SHP_INDEX)

        val asyncJobList = mutableListOf<Single<Any>>()
        getMapFromSPUtilsByResourceId(R.string.shpMapJson)?.forEach {
            val fileName = it.key.toString()
            //这里得到的filePath其实是shp的父目录，需要得到父目录下面的xxx.shp加载进来就行了
            val filePath = it.value.toString()

            File(filePath).listFiles()?.filter { it.name.contains(".shp") }?.forEach {
                val fileName = it.name
                val absolutePath = it.absolutePath

                //异步加载，添加进来
                val asyncJob = Single.create<Any> { emitter ->
                    val shapefileFeatureTable = ShapefileFeatureTable(absolutePath)
                    shapefileFeatureTable.addDoneLoadingListener {
                        val featureLayer = FeatureLayer(shapefileFeatureTable)
                        groupLayer.layers.add(featureLayer)
                        //把name也设置给layer，这样后续图层定位可以用到
                        featureLayer.name = fileName

                        emitter.onSuccess(true)
                    }
                    shapefileFeatureTable.loadAsync()
                }
                asyncJobList.add(asyncJob)
            }
        }
        //全部异步任务完成后再添加进来
        Single.zip(asyncJobList) { objects -> objects }.subscribe({
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_SHP_INDEX)
        }, {
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_SHP_INDEX)
        })
    }

    suspend fun loadFeatureServerToMapView() = withContext(Dispatchers.IO) {
        val groupLayer = GroupLayer()
        addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_FEATURE_SERVER_INDEX)
        val serviceFeatureTable = ServiceFeatureTable("https://services1.arcgis.com/nc9kTdKLRHo08Sxa/arcgis/rest/services/%E6%95%8F%E6%84%9F%E7%89%A9%E5%93%81%E8%A1%A8/FeatureServer/0")
        serviceFeatureTable.addDoneLoadingListener {
            val featureLayer = FeatureLayer(serviceFeatureTable)
            val tableName = serviceFeatureTable.tableName
//            featureLayer.name = "aaa"
            groupLayer.layers.add(featureLayer)

            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_FEATURE_SERVER_INDEX)
        }
        serviceFeatureTable.loadAsync()
    }

    private fun getMapFromSPUtilsByResourceId(sourceId:Int) : Map<*, *>? {
        val mapJson = SPUtils.getInstance().getString(App.app!!.getString(sourceId))
        return Gson().fromJson(mapJson, Map::class.java)
    }

    private fun addGroupLayerToMapViewOperationalLayers(groupLayer: GroupLayer, index:Int) {
        mapView.map?.operationalLayers?.apply {
            //上来直接移除，不管有没有
            try {
                removeAt(index)
            } catch (e: Exception) {
                //e.printStackTrace()
            }
            add(index, groupLayer)
        }
    }

    val gdbMap = mutableMapOf<String, GeodatabaseFeatureTable>()
    suspend fun loadGeodatabaseToMapView() = withContext(Dispatchers.IO){
        val groupLayer = GroupLayer()
        //是空的，groupLayer里面什么都没有只是存放进里面占个位置
        addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_GEODATABASE_INDEX)

        getMapFromSPUtilsByResourceId(R.string.gdbMapJson)?.forEach {
            val fileName = it.key.toString()
            val filePath = it.value.toString()
            val geodatabase = Geodatabase(filePath)
            geodatabase.addDoneLoadingListener {
                val tables = geodatabase.geodatabaseFeatureTables
                tables.forEachIndexed { index, geodatabaseFeatureTable ->
                    val displayName = geodatabaseFeatureTable.displayName
                    gdbMap[if(displayName.contains("_")){
                        displayName.split("_")[1]
                    } else {
                        displayName
                    }] = geodatabaseFeatureTable
                    val featureLayer = FeatureLayer(geodatabaseFeatureTable)
                    featureLayer.name = displayName
                    groupLayer.layers.add(featureLayer)
                }
                addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_GEODATABASE_INDEX)
            }
            geodatabase.loadAsync()
        }
    }

    suspend fun loadGeoJsonToMapView() = withContext(Dispatchers.IO) {
        val groupLayer = GroupLayer()
        getMapFromSPUtilsByResourceId(R.string.geojsonMapJson)?.forEach {
            val fileName = it.key.toString()
            val filePath = it.value.toString()
            val jsonContent = FileUtil.readFile(File(filePath))
            val featureCollection = FeatureCollection.fromJson(jsonContent)
            val featureCollectionLayer = FeatureCollectionLayer(featureCollection)
            featureCollectionLayer.name = fileName
            groupLayer.layers.add(featureCollectionLayer)
        }
        addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_GEOJSON_INDEX)
    }

    /**
     * 根据屏幕中的screenPoint点，来查询feature要素，最后的数字10是最大返回10个要素的意思，
     * 一般写几个就行了，不然缩放到省级别点击地图密集要素不就把所有要素都给你查询出来了
     * mapView.identify有好几个方法的，你还可以更精细化的选择方法来实现你点击查询要素的功能
     */
    fun queryFeatureByScreenCenterPoint(screenPoint: Point) {
        val identifyLayersAsync = mapView.identifyLayersAsync(screenPoint, 10.0, false, 1)
        identifyLayersAsync.addDoneListener {
            identifyLayersAsync.get().forEachIndexed { index, identifyLayerResult ->
                //这个结果是geojson的要素内容
                val sublayerResults = identifyLayerResult.sublayerResults
                if(sublayerResults.isNotEmpty()){
                    sublayerResults.get(0).elements.apply {
                        if(isNotEmpty()){
                            val result = get(0)
                            if(result is Feature){
                                result.featureTable.featureLayer.selectFeature(result)
                                //所有feature的attribute都是懒加载的，如果不来一次空遍历attributes默认里面的value都是空的，初次看到这个效果开始自我怀疑我存储的内容哪去了？？？
                                result.attributes.forEach {
                                    val key = it.key
                                    val value = it.value
                                }
                                queryFeatureLiveData.postValue(result)
                            }
                        }
                    }
                }
                //这个结果是shp和featureServer的要素内容
                identifyLayerResult.elements.forEachIndexed { index, geoElement ->
                    if(geoElement is Feature){
                        //选中要素，高亮显示出来
//                        geoElement.featureTable?.featureLayer?.selectFeature(geoElement)
                        geoElement.attributes.forEach {
                            val key = it.key
                            val value = it.value
                        }
                        queryFeatureLiveData.postValue(geoElement)
                    }
                }

            }
        }
    }

    /**
     * 添加要素，在里面会判断当前是属于什么存储方式
     */
    fun addFeature(geometry: Geometry, layerName: String, dataCollectMap: MutableMap<String, Any?>) {
        //存储类型
        when(getSPUtils().getString(getString(R.string.storage_type), getString(R.string.geojson))){
            getString(R.string.storage_geojson) -> {
                val featureCollectionTable = featureTable[layerName] as FeatureCollectionTable
                val createFeature = featureCollectionTable.createFeature(dataCollectMap, geometry)
                val addFeatureAsync = featureCollectionTable.addFeatureAsync(createFeature)
                applyEdit(addFeatureAsync, object : CallBack {
                    override fun callBack(index: Int) {
                        GlobalScope.launch {
                            //保存到本地
                            featureCollectionSaveToJson(featureCollection)
                        }
                    }
                })
            }
            getString(R.string.storage_shp) -> {
                val shapefileFeatureTable = featureTable[layerName] as ShapefileFeatureTable
                val createFeature = shapefileFeatureTable.createFeature(dataCollectMap, geometry)
                val addFeatureAsync = shapefileFeatureTable.addFeatureAsync(createFeature)
                applyEdit(addFeatureAsync)
            }
            getString(R.string.storage_geodatabase) -> {
                val geodatabaseFeatureTable = featureTable[layerName] as GeodatabaseFeatureTable
                val createFeature = geodatabaseFeatureTable.createFeature(dataCollectMap, geometry)
                val addFeatureAsync = geodatabaseFeatureTable.addFeatureAsync(createFeature)
                applyEdit(addFeatureAsync)
            }
        }
    }

    /**
     * 更新要素
     */
    fun updateFeature(geometry: Geometry, layerName: String, dataCollectMap: MutableMap<String, Any?>, updateFeature: Feature) {
        updateFeature.geometry = geometry
        dataCollectMap.forEach {
            val key = it.key
            val value = it.value
            updateFeature.attributes[key] = value
        }
        //存储类型
        when(getSPUtils().getString(getString(R.string.storage_type), getString(R.string.geojson))){
            getString(R.string.storage_geojson) -> {
                val featureCollectionTable = featureTable[layerName] as FeatureCollectionTable
                val updateFeatureAsync = featureCollectionTable.updateFeatureAsync(updateFeature)
                applyEdit(updateFeatureAsync, object : CallBack {
                    override fun callBack(index: Int) {
                        GlobalScope.launch {
                            featureCollectionSaveToJson(featureCollection)
                        }
                    }
                })
            }
            getString(R.string.storage_shp) -> {
                val shapefileFeatureTable = featureTable[layerName] as ShapefileFeatureTable
                val updateFeatureAsync = shapefileFeatureTable.updateFeatureAsync(updateFeature)
                applyEdit(updateFeatureAsync)
            }
            getString(R.string.storage_geodatabase) -> {
                val geodatabaseFeatureTable = featureTable[layerName] as GeodatabaseFeatureTable
                val updateFeatureAsync = geodatabaseFeatureTable.updateFeatureAsync(updateFeature)
                applyEdit(updateFeatureAsync)
            }
        }
    }


    /**
     * 根据屏幕中心点删除要素
     */
    fun deleteFeatureByScreenCenterPoint() {
        val center = mapView.visibleArea.extent.center
        val screenPoint = mapView.locationToScreen(center)
        val identifyLayersAsync = mapView.identifyLayersAsync(screenPoint, 10.0, false, 1)
        identifyLayersAsync.addDoneListener {
            identifyLayersAsync.get().forEachIndexed { index, identifyLayerResult ->
                val sublayerResults = identifyLayerResult.sublayerResults
                if(sublayerResults.isNotEmpty()){
                    sublayerResults.get(0).elements.apply {
                        if(isNotEmpty()){
                            val result = get(0)
                            if(result is Feature){
                                showConfirmDialog(mapView.context, "提示", "确定删除要素吗") { dialog, which ->
                                    val featureTable = featureTable[result.featureTable.displayName]!!
                                    val deleteFeatureAsync = featureTable.deleteFeatureAsync(result)
                                    applyEdit(deleteFeatureAsync, object : CallBack {
                                        override fun callBack(index: Int) {
                                            GlobalScope.launch {
                                                featureCollectionSaveToJson(featureCollection)
                                            }
                                        }
                                    })
                                }

                            }
                        }
                    }
                }
                identifyLayerResult.elements.forEachIndexed { index, geoElement ->
                    if(geoElement is Feature){
                        val displayName = geoElement.featureTable.tableName
                        showConfirmDialog(mapView.context, "提示", "确定删除要素吗") { dialog, which ->
                            val featureTable = featureTable[displayName]!!
                            val deleteFeatureAsync = featureTable.deleteFeatureAsync(geoElement)
                            applyEdit(deleteFeatureAsync)
                        }
                    }
                }

            }
        }
    }

    /**
     * HomeFragment加载主项目的入口
     */
    suspend fun loadMainProjectToMapView() = withContext(Dispatchers.IO){
        val spUtils = getSPUtils()
        val project = spUtils.getString(getString(R.string.main_project), null)
        if(TextUtils.isEmpty(project)){
            viewModelScope.launch {
                showToast("请配置主项目")
            }
            return@withContext
        }
        //获取存储类型，默认是geojson
        when(spUtils.getString(getString(R.string.storage_type), getString(R.string.storage_geojson))){
            //以geojson存储
            getString(R.string.storage_geojson) -> {
                loadProjectGeoJsonToMapView()
            }
            /**
             * 以shp和geodatabase存储默认不会在这里创建文件，你需要配置完毕项目和里面的各种图层和字段后
             * 回到项目配置，点击项目右上角的 齿轮 菜单，点击生成shp或者geodatabase文件，然后这里就可以用了
             */
            getString(R.string.storage_shp) -> {
                loadProjectShpToMapView()
            }
            getString(R.string.storage_geodatabase) -> {
                loadProjectGeodatabaseToMapView()
            }
            getString(R.string.storage_feature_server) -> {

            }
        }
    }

    /**
     * geoJson 数据操作
     */
    private lateinit var featureCollection: FeatureCollection
    private suspend fun loadProjectGeoJsonToMapView() = withContext(Dispatchers.IO) {
        val groupLayer = GroupLayer()
        //创建FeatureCollectionTable和字段关系
        val mainProjectName = SPUtils.getInstance().getString(App.app!!.getString(R.string.main_project))
        if(TextUtils.isEmpty(mainProjectName)){
            //占位，不然加载后面的featureServer会下标越界
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
            return@withContext
        }

        val project = projectRepository.getProjectByName(mainProjectName)
        //检查本地有没有主专业json文件
        val dataFolder = Environment.getExternalStorageDirectory().absolutePath + File.separator + getString(R.string.app_name) + File.separator + getString(R.string.project_data) + File.separator + getString(R.string.geojson)
        val jsonFile = File(dataFolder, "$mainProjectName.json")
        if(jsonFile.exists()){
            val jsonContent = FileUtil.readFile(jsonFile)
            featureCollection = FeatureCollection.fromJson(jsonContent)
        } else {
            featureCollection = FeatureCollection()
            //项目结构，只能初始化一次
            project.layers.forEachIndexed { index, layer ->
                val fieldList = layer.fields.map { Field.createString(it.field, it.alias, 32) }
                val geometryType = when(layer.type){
                    TYPE_POINT -> GeometryType.POINT
                    TYPE_POLYLINE -> GeometryType.POLYLINE
                    TYPE_POLYGON -> GeometryType.POLYGON
                    else -> GeometryType.POINT
                }
                // TODO: 一定要给项目图层字段中，设置 field 字段，空了不行
                if(fieldList.isNotEmpty()){
                    //根据图层配置来创建FeatureCollectionTable
                    val featureCollectionTable = FeatureCollectionTable(fieldList, geometryType, SpatialReference.create(4326))
                    featureCollectionTable.title = layer.name
                    featureCollection.tables.add(featureCollectionTable)
                }
            }
        }
        //设置符号化相关
        val featureCollectionLayer = FeatureCollectionLayer(featureCollection)
        featureCollectionLayer.addDoneLoadingListener {
            project.layers.forEachIndexed { index, layer ->
                val featureLayer = featureCollectionLayer.layers.filter { it.name == layer.name }[0]
                SymbolUtils.symbol(layer, featureLayer)
            }
            //把featureTable存起来，添加要素的时候用到
            featureCollection.tables.forEachIndexed { index, featureCollectionTable ->
                featureTable[featureCollectionTable.title] = featureCollectionTable
            }
            groupLayer.layers.add(featureCollectionLayer)
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
        }
        featureCollectionLayer.loadAsync()
    }

    /**
     * shp 数据操作
     */
    private suspend fun loadProjectShpToMapView() = withContext(Dispatchers.IO){
        val groupLayer = GroupLayer()
        val mainProjectName = SPUtils.getInstance().getString(App.app!!.getString(R.string.main_project))
        if(TextUtils.isEmpty(mainProjectName)){
            //占位，不然加载后面的featureServer会下标越界
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
            return@withContext
        }

        //为符号化做准备，先把素有的图层配置拿出来
        val mainProject = projectRepository.getProjectByName(mainProjectName)
        val asyncJobList = mutableListOf<Single<Any>>()
        val dataFolder = Environment.getExternalStorageDirectory().absolutePath + File.separator + getString(R.string.app_name) + File.separator + getString(R.string.project_data) + File.separator + getString(R.string.shp) + File.separator + mainProjectName
        File(dataFolder).listFiles()?.forEachIndexed { index, file ->
            val job = Single.create<Any> { emit ->
                //这里得到的file只是每个图层的父目录，还需要遍历该file的子文件xxxx.shp就可以加载了
                val shpfile = file.listFiles().filter { it.name.endsWith(".shp") }[0]
                val shapefileFeatureTable = ShapefileFeatureTable(shpfile.absolutePath)
                shapefileFeatureTable.addLoadStatusChangedListener {
                    when(it.newLoadStatus){
                        LoadStatus.LOADED -> {
                            //加载成功，准备添加入mapView
                            val featureLayer = FeatureLayer(shapefileFeatureTable)
                            featureLayer.name = shpfile.name
                            groupLayer.layers.add(featureLayer)

                            //符号化
                            val layer = mainProject.layers.filter { it.name == file.name }[0]
                            SymbolUtils.symbol(layer, featureLayer)

                            //把featureTable存起来，添加要素的时候用到，xxxxx.shp 用逗号分割拿第一个
                            val filename = file.name.split(".")[0]
                            featureTable[filename] = shapefileFeatureTable

                            emit.onSuccess(true)
                        }
                        LoadStatus.FAILED_TO_LOAD -> {
                            emit.onError(RuntimeException(it.newLoadStatus.name))
                        }
                        else -> {}
                    }
                }
                shapefileFeatureTable.loadAsync()
            }
            asyncJobList.add(job)
        }
        //全部异步任务完成后再添加进来
        Single.zip(asyncJobList) { objects -> objects }.subscribe({
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
        }, {
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
        })
    }

    /**
     * geodatabase 数据操作
     */
    private suspend fun loadProjectGeodatabaseToMapView() = withContext(Dispatchers.IO){
        val groupLayer = GroupLayer()
        val mainProjectName = SPUtils.getInstance().getString(App.app!!.getString(R.string.main_project))
        if(TextUtils.isEmpty(mainProjectName)){
            //占位，不然加载后面的featureServer会下标越界
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
            return@withContext
        }
        val geodatabaseFilePath = Environment.getExternalStorageDirectory().absolutePath + File.separator + getString(R.string.app_name) + File.separator + getString(R.string.project_data) + File.separator + getString(R.string.geodatabase) + File.separator + mainProjectName+".geodatabase"
        val geodatabaseFile = File(geodatabaseFilePath)
        //如果没有创建geodatabase，不能使用
        if(!geodatabaseFile.exists()){
            viewModelScope.launch {
                showToast("主项目未创建geodatabase")
            }
            //占位，不然加载后面的featureServer会下标越界
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
            return@withContext
        }
        //为符号化做准备，先把素有的图层配置拿出来
        val mainProject = projectRepository.getProjectByName(mainProjectName)
        val geodatabase = Geodatabase(geodatabaseFilePath)
        geodatabase.addDoneLoadingListener {
            //加载完毕，获取全部的数据表
            geodatabase.geodatabaseFeatureTables.forEachIndexed { index, geodatabaseFeatureTable ->
                val featureLayer = FeatureLayer(geodatabaseFeatureTable)
                geodatabaseFeatureTable.addDoneLoadingListener {
                    //开始符号化
                    val layer = mainProject.layers.filter { it.name == geodatabaseFeatureTable.tableName }[0]
                    SymbolUtils.symbol(layer, featureLayer)
                }
                groupLayer.layers.add(featureLayer)
                featureTable[geodatabaseFeatureTable.tableName] = geodatabaseFeatureTable
            }
            addGroupLayerToMapViewOperationalLayers(groupLayer, MAP_PROJECT_FEATURE_INDEX)
        }
        geodatabase.loadAsync()
    }

    /**
     * 将featureCollection的内容保存到本地，是geojson
     */
    private suspend fun featureCollectionSaveToJson(featureCollection: FeatureCollection) = withContext(Dispatchers.IO){
        //根据目录来遍历得到所有的文件
        val mainProjectName = SPUtils.getInstance().getString(getString(R.string.main_project))
        val dataFolder = Environment.getExternalStorageDirectory().absolutePath + File.separator + getString(R.string.app_name) + File.separator + getString(R.string.project_data) + File.separator + getString(R.string.geojson)
        FileUtil.write(File(dataFolder, "$mainProjectName.json"), featureCollection.toJson())
    }

    /**
     * 应用操作，是否成功
     */
    private fun applyEdit(listenableFuture: ListenableFuture<Void>, callBack: CallBack? = null){
        listenableFuture.addDoneListener {
            try {
                listenableFuture.get()
                viewModelScope.launch {
                    showToast("操作成功")
                }
                callBack?.let { it.callBack( -1 ) }
            } catch (e: Exception) {
                e.printStackTrace()
                viewModelScope.launch {
                    showToast(e.message!!)
                }
            }
        }
    }

}